#include "inc/SocketManager.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>  // 多路复用 I/O

#include <arpa/inet.h>

#include <unistd.h>

#include <stdio.h>

#include <chrono>
#include <thread>

namespace QD{
    //
    // 创建 socket
    int CreateSocket(SocketInfo *socketInfo){
        int fd = socket(AF_INET, SOCK_STREAM, 0);
        socketInfo->fd = fd;
        if( fd < 0 ){
            QD_LOGE("socket faild: %d", fd);
        } else {
            QD_LOGD("create socket: %d", fd);
        }

        return fd;
    }


    int BindAndListen(SocketInfo *svr, int queue){
        int ret = bind(svr->fd, (struct sockaddr *)&(svr->addr), svr->socklen);
        if(ret == -1) {
            QD_LOGE("bind error");
            return ret;
        }

        ///listen，成功返回0，出错返回-1
        ret = listen(svr->fd, queue);
        if(ret == -1) {
            QD_LOGE("listen error");
            return ret;
        }

        QD_LOGD("bind and listen :%d", ntohs(svr->addr.sin_port));
        return 0;
    }

    int Accept(SocketInfo *svr, SocketInfo *cli){

        memset(cli, 0, sizeof(SocketInfo));
        cli->socklen = sizeof(sizeof(struct sockaddr_in));

        int fd = accept(svr->fd, (struct sockaddr*)&(cli->addr), &cli->socklen);
        cli->fd = fd;
        if( fd  < 0 ) {
            perror("client connect error !");
        } else {
            //QD_LOGD("client:%d connect port: %d", fd, ntohs(cli->addr.sin_port));
        }
        return fd;
    }

    int Connect(SocketInfo *svr){
        int resConn = connect(svr->fd, (struct sockaddr *)&(svr->addr), svr->socklen);

        if (resConn < 0) {
            perror("connect faild:%d");
            QD_LOGE("connect faild:%d", resConn);
        } else {
            QD_LOGD("connect success %d ",ntohs(svr->addr.sin_port));
        }

        return resConn;

    }

    int Close(SocketInfo *socketInfo){
        close(socketInfo->fd);
        return 0;
    }


    int CreateSocketInfo(SocketInfo *sockInfo, const char *_ipStr, const int _port, SocketType _type){

        memset(sockInfo, 0, sizeof(SocketInfo));

        sockInfo->socklen = sizeof(struct sockaddr_in);

        if(_type == CLIENT){
            //return 0;
        }

        sockInfo->addr.sin_family = AF_INET;
        sockInfo->addr.sin_addr.s_addr = inet_addr(_ipStr);
        sockInfo->addr.sin_port = htons(_port);

        sockInfo->type = _type;

        return 0;
    }

    int Recv(int fd, void *buff, int size, int flags){
        return 0;
    }

    int Send(int fd, void *buff, int size, int flags){
        return 0;
    }


}   /* namespace QD { */


EndPoint::EndPoint(const char *_ip, const int _port){

    memset(&mAddr, 0, sizeof(struct sockaddr_in));

    mFd = socket(AF_INET, SOCK_STREAM, 0);

    mSocklen = sizeof(struct sockaddr_in);

    mAddr.sin_family = AF_INET;
    mAddr.sin_addr.s_addr = inet_addr(_ip);

    mAddr.sin_port = htons(_port);
}
EndPoint::~EndPoint(){
    close(mFd);
}

EndPoint * EndPoint::RegistServer(){
    int ret = bind(mFd, (struct sockaddr *)&(mAddr), mSocklen);
    if(ret == -1) {
        QD_LOGE("bind error");
        return nullptr;
    }

    ///listen，成功返回0，出错返回-1
    ret = listen(mFd, 1024);
    if(ret == -1) {
        QD_LOGE("listen error");
        return nullptr;
    }

    QD_LOGD("bind and listen :%d", ntohs(mAddr.sin_port));
    return this;
}


EndPoint * EndPoint::Accept(){

    EndPoint *cli = new EndPoint;
    cli->mSocklen = sizeof(sizeof(struct sockaddr_in));

    int fd = accept(mFd, (struct sockaddr*)&cli->mAddr, &cli->mSocklen);

    cli->mFd = fd;

    if( fd  < 0 ) {
        perror("client connect error !");
    } else {
        QD_LOGD("client:%d connect port: %d", cli->mFd, ntohs(cli->mAddr.sin_port));
    }
    return cli;
}

EndPoint *EndPoint::Connect(){

    //QD_LOGE("%d %d %d %d",mFd, mAddr.sin_family, mAddr.sin_addr.s_addr, mAddr.sin_port);

    int resConn = connect(mFd, (struct sockaddr *)&mAddr, mSocklen);

    if (resConn < 0) {
        perror("connect faild");
        QD_LOGE("connect faild:%d", resConn);

        return nullptr;
    } else {
        QD_LOGD("connect success %d ",ntohs(mAddr.sin_port));
    }

    return this;
}

void EndPoint::Request(void *req, int reqSize, void *res, int resSize){
    send(mFd, req, reqSize, 0);
    recv(mFd, res, resSize, 0);
}

